App.require(function () {
    function getDefaultObject(defaultObj, obj) {
        if (obj) {
            var sDefault = {};
            for (var p in obj) {
                if (obj[p] != sDefault) {
                    defaultObj[p] = obj[p];
                }
            }
        }
    }

    function isTypedArray(arg) {
        return (arg && (typeof arg.buffer != "undefined") && (arg.buffer instanceof ArrayBuffer));
    }

    var typeSize = {};
    typeSize[WebGLRenderingContext.NONE] = 0;
    typeSize[WebGLRenderingContext.UNSIGNED_BYTE] = Uint8Array.BYTES_PER_ELEMENT;
    typeSize[WebGLRenderingContext.BYTE] = Int8Array.BYTES_PER_ELEMENT;
    typeSize[WebGLRenderingContext.UNSIGNED_SHORT] = Uint16Array.BYTES_PER_ELEMENT;
    typeSize[WebGLRenderingContext.SHORT] = Int16Array.BYTES_PER_ELEMENT;
    typeSize[WebGLRenderingContext.UNSIGNED_INT] = Uint32Array.BYTES_PER_ELEMENT;
    typeSize[WebGLRenderingContext.INT] = Int32Array.BYTES_PER_ELEMENT;
    typeSize[WebGLRenderingContext.FLOAT] = Float32Array.BYTES_PER_ELEMENT;

    var typeToTypedArrayConstructor = {};
    typeToTypedArrayConstructor[WebGLRenderingContext.NONE] = ArrayBuffer;
    typeToTypedArrayConstructor[WebGLRenderingContext.UNSIGNED_BYTE] = Uint8Array;
    typeToTypedArrayConstructor[WebGLRenderingContext.BYTE] = Int8Array;
    typeToTypedArrayConstructor[WebGLRenderingContext.UNSIGNED_SHORT] = Uint16Array;
    typeToTypedArrayConstructor[WebGLRenderingContext.SHORT] = Int16Array;
    typeToTypedArrayConstructor[WebGLRenderingContext.UNSIGNED_INT] = Uint32Array;
    typeToTypedArrayConstructor[WebGLRenderingContext.INT] = Int32Array;
    typeToTypedArrayConstructor[WebGLRenderingContext.FLOAT] = Float32Array;

    function Model(gl, descriptor, options) {
        options = getDefaultObject({}, options);
        if (descriptor && ("vertices" in descriptor)) {
            descriptor = Model._createSimpleDescriptor(descriptor);
        }

        this._descriptor = Model._fixDescriptor(descriptor);
        this._gl = null;
        this._renderData = {};

        if (gl) {
            this.updateGL(gl, options);
            this.updateRenderData();
        }
    }

    Model.prototype = {
        constructor: Model,
        get descriptor() {
            return this._descriptor;
        },

        get isReady() {
            return !!this._descriptor;
        },

        get gl() {
            return this._gl;
        },

        get renderData() {
            return this._renderData;
        },
        updateTypedArrays: function () {
            var d = this._descriptor;
            if (!d) return false;

            var buffer = null;
            var ctor = null;

            var vertexBuffers = d.data.vertexBuffers;
            for (var x in vertexBuffers) {
                buffer = vertexBuffers[x];
                if (!buffer.untypedArray) continue;
                ctor = typeToTypedArrayConstructor[buffer.type];
                buffer.typedArray = new ctor(buffer.untypedArray);
            }

            var indexBuffers = d.data.indexBuffers;
            for (var x in indexBuffers) {
                buffer = indexBuffers[x];
                if (!buffer.untypedArray) continue;
                ctor = typeToTypedArrayConstructor[buffer.type];
                buffer.typedArray = new ctor(buffer.untypedArray);
            }

            return true;
        },
        updateGL: function (gl, options) {
            if (!gl) return false;

            var d = this._descriptor;
            if (!d) return false;

            this._gl = gl;

            var buffer = null;
            var typedArray = null;
            var ctor = null;

            var bufferOptions = getDefaultObject({
                data: null,
                usage: {}
            }, options);
            bufferOptions.data = null;

            for (var x in d.data.vertexBuffers) {
                buffer = d.data.vertexBuffers[x];
                bufferOptions.data = buffer.typedArray;
                if (!bufferOptions.data) {
                    ctor = typeToTypedArrayConstructor[buffer.type];
                    bufferOptions.data = new ctor(buffer.untypedArray);
                }
                if (buffer.glBuffer) {
                    buffer.glBuffer.destroy();
                    buffer.glBuffer = null;
                }
                buffer.glBuffer = new SpiderGL.WebGL.VertexBuffer(gl, bufferOptions);
            }

            for (var x in d.data.indexBuffers) {
                buffer = d.data.indexBuffers[x];
                bufferOptions.data = buffer.typedArray;
                if (!bufferOptions.data) {
                    ctor = SpiderGL.Type.typeToTypedArrayConstructor[buffer.type];
                    bufferOptions.data = new ctor(buffer.untypedArray);
                }
                if (buffer.glBuffer) {
                    buffer.glBuffer.destroy();
                    buffer.glBuffer = null;
                }
                buffer.glBuffer = new SpiderGL.WebGL.IndexBuffer(gl, bufferOptions);
            }

            var stream = null;

            for (var x in d.access.vertexStreams) {
                stream = d.access.vertexStreams[x];
                stream.glType = stream.type;
            }

            for (var x in d.access.primitiveStreams) {
                stream = d.access.primitiveStreams[x];
                stream.glMode = stream.mode;
                stream.glType = stream.type;
            }

            return true;
        },
        destroyGL: function () {
            var d = this._descriptor;
            if (!d) return false;

            var buffer = null;

            for (var x in d.data.vertexBuffers) {
                buffer = d.data.vertexBuffers[x];
                if (buffer.glBuffer) {
                    buffer.glBuffer.destroy();
                    buffer.glBuffer = null;
                }
            }

            for (var x in d.data.indexBuffers) {
                buffer = d.data.indexBuffers[x];
                if (buffer.glBuffer) {
                    buffer.glBuffer.destroy();
                    buffer.glBuffer = null;
                }
            }
        },
        updateRenderData: function () {
            var d = this._descriptor;
            if (!d) return false;

            var renderData = {
                partMap: {}
            };

            for (var partName in d.logic.parts) {
                var part = d.logic.parts[partName];
                var chunkNames = part.chunks;
                var partInfo = {};
                renderData.partMap[partName] = partInfo;

                for (var i = 0, n = chunkNames.length; i < n; ++i) {
                    var chunkName = chunkNames[i];
                    var chunk = d.semantic.chunks[chunkName];
                    var chunkInfo = {};
                    partInfo[chunkName] = chunkInfo;

                    var techniques = chunk.techniques;
                    for (var techniqueName in techniques) {
                        var techique = techniques[techniqueName];
                        var techiqueInfo = {
                            vertexStreams: {
                                buffered: [],
                                constant: []
                            },
                            primitiveStreams: {}
                        };
                        chunkInfo[techniqueName] = techiqueInfo;

                        var binding = d.semantic.bindings[techique.binding];

                        var streams = binding.vertexStreams;
                        var bufferMap = {};
                        for (var semantic in streams) {
                            var streamNames = streams[semantic];
                            for (var j = 0, m = streamNames.length; j < m; ++j) {
                                var streamName = streamNames[j];
                                var stream = d.access.vertexStreams[streamName];
                                var streamInfo = {
                                    semantic: semantic,
                                    index: j,
                                    stream: stream
                                }
                                var bufferName = stream.buffer;
                                if (bufferName) {
                                    bufferMap[bufferName] = bufferMap[bufferName] || [];
                                    bufferMap[bufferName].push(streamInfo);
                                } else {
                                    techiqueInfo.vertexStreams.constant.push(streamInfo);
                                }
                            }
                        }
                        for (var bufferName in bufferMap) {
                            var bufferInfo = {
                                buffer: d.data.vertexBuffers[bufferName],
                                streams: bufferMap[bufferName].slice()
                            };
                            techiqueInfo.vertexStreams.buffered.push(bufferInfo);
                        }

                        var streams = binding.primitiveStreams;
                        for (var semantic in streams) {
                            var bufferMap = {};
                            var primitiveStreamsInfo = {
                                buffered: [],
                                array: []
                            };
                            techiqueInfo.primitiveStreams[semantic] = primitiveStreamsInfo;

                            var streamNames = streams[semantic];
                            for (var j = 0, m = streamNames.length; j < m; ++j) {
                                var streamName = streamNames[j];
                                var stream = d.access.primitiveStreams[streamName];
                                var bufferName = stream.buffer;
                                if (bufferName) {
                                    bufferMap[bufferName] = bufferMap[bufferName] || [];
                                    bufferMap[bufferName].push(stream);
                                } else {
                                    primitiveStreamsInfo.array.push(stream);
                                }
                            }
                            for (var bufferName in bufferMap) {
                                var bufferInfo = {
                                    buffer: d.data.indexBuffers[bufferName],
                                    streams: bufferMap[bufferName].slice()
                                };
                                primitiveStreamsInfo.buffered.push(bufferInfo);
                            }
                        }
                    }
                }
            }

            this._renderData = renderData;
        }
    };

    Model.DEFAULT_VERTEX_STREAM_SIZE = 3;
    Model.DEFAULT_VERTEX_STREAM_TYPE = WebGLRenderingContext.FLOAT;
    Model.DEFAULT_VERTEX_STREAM_NORMALIZED = false;
    Model.DEFAULT_VERTEX_STREAM_STRIDE = 0;
    Model.DEFAULT_VERTEX_STREAM_OFFSET = 0;
    Model.DEFAULT_PRIMITIVE_STREAM_MODE = WebGLRenderingContext.TRIANGLES;
    Model.DEFAULT_PRIMITIVE_STREAM_FIRST = 0;
    Model.DEFAULT_PRIMITIVE_STREAM_COUNT = -1;
    Model.DEFAULT_PRIMITIVE_STREAM_TYPE = WebGLRenderingContext.UNSIGNED_SHORT;
    Model.DEFAULT_PRIMITIVE_STREAM_OFFSET = 0;
    Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP = {};
    Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["position"] = {
        size: 3,
        type: WebGLRenderingContext.FLOAT,
        normalized: false,
        semantic: "POSITION",
        index: 0,
        value: [0.0, 0.0, 0.0, 1.0]
    };
    Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["normal"] = {
        size: 3,
        type: WebGLRenderingContext.FLOAT,
        normalized: false,
        semantic: "NORMAL",
        index: 0,
        value: [0.0, 0.0, 1.0, 0.0]
    };
    Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["color"] = {
        size: 4,
        type: WebGLRenderingContext.UNSIGNED_BYTE,
        normalized: true,
        semantic: "COLOR",
        index: 0,
        value: [0, 0, 0, 255]
    };
    Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["texcoord"] = {
        size: 2,
        type: WebGLRenderingContext.FLOAT,
        normalized: false,
        semantic: "TEXCOORD",
        index: 0,
        value: [0.0, 0.0, 0.0, 1.0]
    };
    Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["user"] = {
        size: 3,
        type: WebGLRenderingContext.FLOAT,
        normalized: false,
        semantic: "USER",
        index: 0,
        value: [0.0, 0.0, 0.0, 1.0]
    };

    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP = {};
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["triangles"] = {
        mode: WebGLRenderingContext.TRIANGLES,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "FILL"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["triangleStrip"] = {
        mode: WebGLRenderingContext.TRIANGLE_STRIP,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "FILL"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["triangleFan"] = {
        mode: WebGLRenderingContext.TRIANGLE_FAN,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "FILL"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["lines"] = {
        mode: WebGLRenderingContext.LINES,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "LINE"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["lineStrip"] = {
        mode: WebGLRenderingContext.LINE_STRIP,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "LINE"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["lineLoop"] = {
        mode: WebGLRenderingContext.LINE_LOOP,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "LINE"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["points"] = {
        mode: WebGLRenderingContext.POINTS,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "POINT"
    };
    Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["user"] = {
        mode: WebGLRenderingContext.TRIANGLES,
        type: WebGLRenderingContext.UNSIGNED_SHORT,
        count: -1,
        semantic: "FILL"
    };

    Model._fixDescriptor = function (d) {
        d = getDefaultObject({
            version: "0.0.0.1 EXP",
            meta: null,
            data: null,
            access: null,
            semantic: null,
            logic: null
        }, d);

        d.meta = this._fixDescriptorMeta(d.meta);
        d.data = this._fixDescriptorData(d.data);
        d.access = this._fixDescriptorAccess(d.access);
        d.semantic = this._fixDescriptorSemantic(d.semantic);
        d.logic = this._fixDescriptorLogic(d.logic);

        return d;
    };

    Model._fixDescriptorMeta = function (d) {
        d = getDefaultObject({
            author: null,
            date: null,
            description: null
        }, d);
        return d;
    };

    Model._fixDescriptorData = function (d) {
        d = getDefaultObject({
            vertexBuffers: null,
            indexBuffers: null
        }, d);

        d.vertexBuffers = this._fixDescriptorDataVertexBuffers(d.vertexBuffers);
        d.indexBuffers = this._fixDescriptorDataIndexBuffers(d.indexBuffers);

        return d;
    };

    Model._fixDescriptorDataVertexBuffers = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorDataVertexBuffer(d[x]);
        }
        return d;
    };

    Model._fixDescriptorDataVertexBuffer = function (d) {
        return this._fixDescriptorDataBuffer(d);
    };

    Model._fixDescriptorDataIndexBuffers = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorDataIndexBuffer(d[x]);
        }
        return d;
    };

    Model._fixDescriptorDataIndexBuffer = function (d) {
        return this._fixDescriptorDataBuffer(d);
    };

    Model._fixDescriptorDataBuffer = function (d) {
        d = getDefaultObject({
            type: WebGLRenderingContext.NONE,
            glType: WebGLRenderingContext.NONE,
            untypedArray: null,
            typedArray: null,
            glBuffer: null
        }, d);
        return d;
    };

    Model._fixDescriptorAccess = function (d) {
        d = getDefaultObject({
            vertexStreams: null,
            primitiveStreams: null
        }, d);

        d.vertexStreams = this._fixDescriptorAccessVertexStreams(d.vertexStreams);
        d.primitiveStreams = this._fixDescriptorAccessPrimitiveStreams(d.primitiveStreams);

        return d;
    };

    Model._fixDescriptorAccessVertexStreams = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorAccessVertexStream(d[x]);
        }
        return d;
    };

    Model._fixDescriptorAccessVertexStream = function (d) {
        d = getDefaultObject({
            buffer: null,
            size: 3,
            type: WebGLRenderingContext.FLOAT,
            glType: WebGLRenderingContext.FLOAT,
            normalized: false,
            stride: 0,
            offset: 0
        }, d);
        return d;
    };

    Model._fixDescriptorAccessPrimitiveStreams = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorAccessPrimitiveStream(d[x]);
        }
        return d;
    };

    Model._fixDescriptorAccessPrimitiveStream = function (d) {
        d = getDefaultObject({
            buffer: null,
            mode: WebGLRenderingContext.TRIANGLES,
            first: 0,
            count: -1,
            type: WebGLRenderingContext.UNSIGNED_SHORT,
            glType: WebGLRenderingContext.UNSIGNED_SHORT,
            offset: 0
        }, d);
        return d;
    };

    Model._fixDescriptorSemantic = function (d) {
        d = getDefaultObject({
            bindings: null,
            chunks: null
        }, d);

        d.bindings = this._fixDescriptorSemanticBindings(d.bindings);
        d.chunks = this._fixDescriptorSemanticChunks(d.chunks);

        return d;
    };

    Model._fixDescriptorSemanticBindings = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorSemanticBinding(d[x]);
        }
        return d;
    };

    Model._fixDescriptorSemanticBinding = function (d) {
        d = getDefaultObject({
            vertexStreams: null,
            primitiveStreams: null
        }, d);

        d.vertexStreams = this._fixDescriptorSemanticBindingVertexStreams(d.vertexStreams);
        d.primitiveStreams = this._fixDescriptorSemanticBindingPrimitiveStreams(d.primitiveStreams);

        return d;
    };

    Model._fixDescriptorSemanticBindingVertexStreams = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorSemanticBindingVertexStream(d[x]);
        }
        return d;
    };

    Model._fixDescriptorSemanticBindingVertexStream = function (d) {
        if (!d) return null;
        if (Array.isArray(d)) return d.slice();
        return [d];
    };

    Model._fixDescriptorSemanticBindingPrimitiveStreams = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorSemanticBindingPrimitiveStream(d[x]);
        }
        return d;
    };

    Model._fixDescriptorSemanticBindingPrimitiveStream = function (d) {
        if (!d) return null;
        if (Array.isArray(d)) return d.slice();
        return [d];
    };

    Model._fixDescriptorSemanticChunks = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorSemanticChunk(d[x]);
        }
        return d;
    };

    Model._fixDescriptorSemanticChunk = function (d) {
        d = getDefaultObject({
            techniques: null
        }, d);

        d.techniques = this._fixDescriptorSemanticChunkTechniques(d.techniques);

        return d;
    };

    Model._fixDescriptorSemanticChunkTechniques = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorSemanticChunkTechnique(d[x]);
        }
        return d;
    };

    Model._fixDescriptorSemanticChunkTechnique = function (d) {
        d = getDefaultObject({
            binding: null
        }, d);
        return d;
    };

    Model._fixDescriptorLogic = function (d) {
        d = getDefaultObject({
            parts: null
        }, d);

        d.parts = this._fixDescriptorLogicParts(d.parts);

        return d;
    };

    Model._fixDescriptorLogicParts = function (d) {
        d = getDefaultObject({}, d);
        for (var x in d) {
            d[x] = this._fixDescriptorLogicPart(d[x]);
        }
        return d;
    };

    Model._fixDescriptorLogicPart = function (d) {
        d = getDefaultObject({
            chunks: null
        }, d);

        d.chunks = this._fixDescriptorLogicPartChunks(d.chunks);

        return d;
    };

    Model._fixDescriptorLogicPartChunks = function (d) {
        if (!d) return null;
        if (Array.isArray(d)) return d.slice();
        return [d];
    };

    Model._createSimpleDescriptor = function (options) {
        options = getDefaultObject({
            vertices: null,
            primitives: null,
            options: null
        }, options);

        var bindingName = "mainBinding";
        var chunkName = "mainChunk";
        var partName = "mainPart";
        var vertexBufferSuffix = "VertexBuffer";
        var indexBufferSuffix = "IndexBuffer";

        var d = {
            data: {
                vertexBuffers: {},
                indexBuffers: {},
            },
            access: {
                vertexStreams: {},
                primitiveStreams: {}
            },
            semantic: {
                bindings: {},
                chunks: {}
            },
            logic: {
                parts: {}
            }
        };

        var binding = {
            vertexStreams: {},
            primitiveStreams: {}
        };
        d.semantic.bindings[bindingName] = binding;

        var chunk = {
            techniques: {
                "common": {
                    binding: bindingName
                }
            }
        };
        d.semantic.chunks[chunkName] = chunk;

        var part = {
            chunks: [chunkName]
        };
        d.logic.parts[partName] = part;

        var minBufferedCount = -1;
        var hasBuffered = false;
        var hasConstant = false;

        for (var x in options.vertices) {
            var src = options.vertices[x];
            if (!src) continue;

            if (Array.isArray(src) || isTypedArray(src) || src instanceof ArrayBuffer) {
                src = {
                    data: src
                };
            }

            var map = Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP[x];
            var mapSemantic = null;
            if (!map) {
                map = Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["user"];
                mapSemantic = x.toUpperCase();
            } else {
                mapSemantic = map.semantic;
            }

            var info = getDefaultObject({
                size: map.size,
                type: map.type,
                normalized: map.normalized,
                semantic: mapSemantic,
                index: map.index,
                data: null,
                value: map.value.slice()
            }, src);

            var accessor = {
                buffer: null,
                size: info.size,
                type: info.type,
                normalized: info.normalized,
                stride: 0,
                offset: 0,
                value: info.value.slice(),
            };

            if (info.data) {
                var buffer = {
                    type: info.type
                };
                var count = 0;
                if (Array.isArray(info.data)) {
                    buffer.untypedArray = info.data;
                    count = buffer.untypedArray.length / accessor.size;
                } else if (isTypedArray(src) || src instanceof ArrayBuffer) {
                    buffer.typedArray = info.data;
                    count = (buffer.typedArray.byteLength - accessor.offset) / (accessor.size * typeSize[accessor.type]);
                } else {
                    continue;
                }
                count = Math.floor(count);
                hasBuffered = true;
                minBufferedCount = (minBufferedCount >= 0) ? (Math.min(minBufferedCount, count)) : (count);
                var bufferName = x + vertexBufferSuffix;
                d.data.vertexBuffers[bufferName] = buffer;
                accessor.buffer = bufferName;
            } else {
                hasConstant = true;
            }

            var streamName = x;
            d.access.vertexStreams[streamName] = accessor;

            var streams = new Array(info.index + 1);
            streams[info.index] = streamName;
            binding.vertexStreams[info.semantic] = streams;
        }

        var minCount = 0;
        if (hasBuffered) {
            minCount = minBufferedCount;
        } else if (hasConstant) {
            minCount = 1;
        }

        var optionsPrimitives = options.primitives;
        if (typeof optionsPrimitives == "string") {
            optionsPrimitives = [optionsPrimitives];
        }
        if (Array.isArray(optionsPrimitives)) {
            var op = optionsPrimitives;
            optionsPrimitives = {};
            for (var i = 0, n = op.length; i < n; ++i) {
                var pn = op[i];
                if (!this.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP[pn]) continue;
                optionsPrimitives[pn] = {};
            }
        }

        for (var x in optionsPrimitives) {
            var src = optionsPrimitives[x];
            if (!src) continue;

            if (Array.isArray(src) || isTypedArray(src) || src instanceof ArrayBuffer) {
                src = {
                    data: src
                };
            }

            var map = this.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP[x];
            if (!map) map = this.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["user"];

            var info = getDefaultObject({
                mode: map.mode,
                type: map.type,
                count: ((map.count >= 0) ? (map.count) : (minCount)),
                semantic: map.semantic
            }, src);

            var accessor = {
                buffer: null,
                mode: info.mode,
                first: 0,
                count: info.count,
                type: info.type,
                offset: 0
            };

            if (info.data) {
                var buffer = {
                    type: info.type
                };
                var count = 0
                if (Array.isArray(info.data)) {
                    buffer.untypedArray = info.data;
                    count = buffer.untypedArray.length;
                } else if (isTypedArray(src) || src instanceof ArrayBuffer) {
                    buffer.typedArray = info.data;
                    count = (buffer.typedArray.byteLength - accessor.offset) / typeSize[accessor.type];
                } else {
                    continue;
                }
                count = Math.floor(count);
                var bufferName = x + indexBufferSuffix;
                d.data.indexBuffers[bufferName] = buffer;
                accessor.buffer = bufferName;
                accessor.count = count;
            }

            var streamName = x;
            d.access.primitiveStreams[streamName] = accessor;

            var streams = new Array(1);
            streams[0] = streamName;
            binding.primitiveStreams[info.semantic] = streams;
        }

        return d;
    };
})